﻿using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Activation;
using Microsoft.Commerce.Common.MessageBuilders;
using Microsoft.Commerce.Contracts;
using Microsoft.Commerce.Contracts.Messages;
using MusicWorks.Service.DataContracts;
using MusicWorks.Service.Contracts;

namespace MusicWorks.Service
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class CatalogService : BaseServiceClass, ICatalogService
    {
        public Product GetProduct(string productId, string catalogId)
        {
            Product result = null;

            var queryBuilder = new CommerceQuery<Product, CommerceModelSearch<Product>>();
            queryBuilder.SearchCriteria.Model.CatalogId = catalogId;
            queryBuilder.SearchCriteria.Model.Id = productId;

            var queryVariants = new CommerceQueryRelatedItem<Variant>(Product.RelationshipName.Variants);
            // var queryCategory = new CommerceQueryRelatedItem<Category>(HierarchicalCatalogEntity.RelationshipName.ParentCategories);
            // var queryCrossSells = new CommerceQueryRelatedItem<Product>(HierarchicalCatalogEntity.RelationshipName.RelatedProducts);

            queryBuilder.RelatedOperations.Add(queryVariants);
            // queryBuilder.RelatedOperations.Add(queryCategory);
            // queryBuilder.RelatedOperations.Add(queryCrossSells);


            Broker.AddRequest(queryBuilder);
            Broker.Execute();
            var response = (CommerceQueryOperationResponse)Broker.Responses.FirstOrDefault();

            if (response.CommerceEntities != null && response.CommerceEntities.Count > 0)
                result = response.CommerceEntities[0];

            return result;
        }

        public IEnumerable<Category> GetTopLevelCategories(string catalogId)
        {
            return GetChildCategories(catalogId, null);
        }

        public IEnumerable<Category> GetChildCategories(string catalogId, string parentCategoryId)
        {
            List<Category> result = null;

            var queryBuilder = new CommerceQuery<Category, CommerceModelSearch<Category>>();
            queryBuilder.SearchCriteria.Model.CatalogId = catalogId;
            queryBuilder.SearchCriteria.Model.Id = parentCategoryId;

            var queryCategories = new CommerceQueryRelatedItem<Category>(Category.RelationshipName.ChildCategories);
            queryBuilder.RelatedOperations.Add(queryCategories);

            Broker.AddRequest(queryBuilder);
            Broker.Execute();

            var response = (CommerceQueryOperationResponse)Broker.Responses.FirstOrDefault();

            if (response.CommerceEntities != null && response.CommerceEntities.Count > 0)
            {
                var rootCategory = (Category)response.CommerceEntities[0];
                result = new List<Category>();
                foreach (CommerceRelationship category in rootCategory.ChildCategories)
                {
                    result.Add(category.Target);
                }
            }

            return result;
        }

        public IEnumerable<Product> GetProductsByCategory(string catalogId, string parentCategoryId)
        {
            var categoryQuery = new CommerceQuery<Category, CommerceModelSearch<Category>>();

            categoryQuery.SearchCriteria.Model.Id = parentCategoryId;
            categoryQuery.SearchCriteria.Model.CatalogId = catalogId;

            var queryProducts = new CommerceQueryRelatedItem<Product>(Category.RelationshipName.ChildProducts);

            queryProducts.SearchCriteria.FirstItemIndex = 0;
            queryProducts.SearchCriteria.NumberOfItemsToReturn = 50;

            categoryQuery.RelatedOperations.Add(queryProducts);

            Broker.AddRequest(categoryQuery);
            Broker.Execute();
            var response = (CommerceQueryOperationResponse)Broker.Responses.FirstOrDefault();

            if (response.CommerceEntities.Count > 0)
            {
                var products = new List<Product>();
                var category = (Category)response.CommerceEntities[0];
                if (category.ChildProducts == null)
                    return null;

                foreach (CommerceRelationship product in category.ChildProducts)
                {
                    products.Add(product.Target);
                }

                return products;
            }

            return null;
        }


        //TODO: Should this be moved into its own service to provide OpenSearch methods too?
        public IEnumerable<Product> DoProductQuerySearch(string catalogName, string searchPhrase,
                                                         string orderKey, SortDirection sortOrder,
                                                         int recordIndex, int recordsPerPage)
        {
            var products = new List<Product>();
            var requiredProperties = new List<string>();

            var query = new CommerceQuery<CatalogEntity, CommerceCatalogFullTextSearchBuilder>();
            query.SearchCriteria.Catalogs.Add(catalogName);
            query.SearchCriteria.FirstItemIndex = recordIndex;
            query.SearchCriteria.FullTextSearchType = CommerceFullTextSearchType.FreeText;
            query.SearchCriteria.NumberOfItemsToReturn = recordsPerPage;
            query.SearchCriteria.Phrase = searchPhrase;
            query.SearchCriteria.ReturnTotalItemCount = true;

            if (!string.IsNullOrEmpty(orderKey))
            {
                query.SearchCriteria.SortProperties.Add(new CommerceSortProperty(Product.ModelNameDefinition, orderKey,
                                                                                 sortOrder));
            }

            query.SearchCriteria.TypesToSearch = CommerceCatalogEntityTypes.Product;

            CommerceResponse response = Broker.ProcessRequest(query.ToRequest());
            var queryResponse = response.OperationResponses[0] as CommerceQueryOperationResponse;

            // No results.  Return the empty list
            if (queryResponse.CommerceEntities.Count == 0)
                return products;


            // Prepare a multi-operation to retrieve the product variants
            var multiOperation = new CommerceMultiOperation();
            foreach (Product product in queryResponse.CommerceEntities)
            {
                var productQuery = new CommerceQuery<Product>(Product.ModelNameDefinition);
                productQuery.SearchCriteria.Model.Id = product.Id;
                productQuery.SearchCriteria.Model.CatalogId = catalogName;

                var variantQuery = new CommerceQueryRelatedItem<Variant>(Product.RelationshipName.Variants);
                productQuery.RelatedOperations.Add(variantQuery);
                multiOperation.Add(productQuery);
            }

            CommerceResponse variantsResponse = Broker.ProcessRequest(multiOperation.ToRequest());

            if (variantsResponse.OperationResponses.Count != queryResponse.CommerceEntities.Count)
                return null;


            foreach (CommerceQueryOperationResponse product in variantsResponse.OperationResponses)
                products.Add((Product)product.CommerceEntities[0]);

            return products;
        }
    }
}